package github.flandre.examplemod.common.guiblock.tileentity;

import com.google.common.collect.Queues;
import com.mojang.datafixers.DSL;
import github.flandre.examplemod.common.energy.tileentity.FEDemoGeneratorTileEntity;
import github.flandre.examplemod.common.guiblock.MyIntArray;
import github.flandre.examplemod.common.guiblock.block.ExampleBurnMachine;
import github.flandre.examplemod.common.guiblock.containers.ExampleBurnMachineContainers;
import github.flandre.examplemod.examplemod;
import net.minecraft.block.BlockState;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.entity.player.PlayerInventory;
import net.minecraft.inventory.container.Container;
import net.minecraft.inventory.container.INamedContainerProvider;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.CompoundNBT;
import net.minecraft.tileentity.ITickableTileEntity;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.tileentity.TileEntityType;
import net.minecraft.util.Direction;
import net.minecraft.util.text.ITextComponent;
import net.minecraft.util.text.TranslationTextComponent;
import net.minecraft.world.World;
import net.minecraftforge.common.ForgeHooks;
import net.minecraftforge.common.capabilities.Capability;
import net.minecraftforge.common.util.LazyOptional;
import net.minecraftforge.energy.CapabilityEnergy;
import net.minecraftforge.energy.IEnergyStorage;
import net.minecraftforge.event.RegistryEvent;
import net.minecraftforge.eventbus.api.SubscribeEvent;
import net.minecraftforge.fml.common.Mod;
import net.minecraftforge.items.CapabilityItemHandler;
import net.minecraftforge.items.IItemHandler;
import net.minecraftforge.items.ItemStackHandler;
import net.minecraftforge.registries.ObjectHolder;
import org.jetbrains.annotations.NotNull;

import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.util.Objects;
import java.util.Queue;

//机器实体，功能都在这里
@Mod.EventBusSubscriber(bus = Mod.EventBusSubscriber.Bus.MOD)
public class ExampleBurnMachineTileEntity extends TileEntity implements ITickableTileEntity, INamedContainerProvider {

    public static final String NAME = "examplemod:burn_machine";
    //添加物品槽
    //private Inventory inventory = new Inventory(1);
    private final ItemStackHandler UP = new ItemStackHandler(1)
    {
        @Override
        protected void onContentsChanged(int slot) {
            ExampleBurnMachineTileEntity.this.markDirty(); //保存数据
        }
    };

    @ObjectHolder(NAME)
    public static TileEntityType<FEDemoGeneratorTileEntity> TILE_ENTITY_TYPE;

    //机器实体注册
    @SubscribeEvent
    public static void onRegisterTileEntityType(@Nonnull RegistryEvent.Register<TileEntityType<?>> event)
    {
        event.getRegistry().register(TileEntityType.Builder.create(ExampleBurnMachineTileEntity::new,ExampleBurnMachine.BLOCK)
                .build(DSL.remainderType()).setRegistryName(NAME));
    }

    public ExampleBurnMachineTileEntity() {
        super(TILE_ENTITY_TYPE);
    }

    //保存
    @Override
    public void read(@NotNull BlockState state, CompoundNBT compound) {
        this.energy = compound.getInt("BurnEnergy");
        this.UP.deserializeNBT(compound.getCompound("UP"));
        this.itemNumber.set(0, this.UP.getStackInSlot(0).getCount());
        this.itemNumber.set(1, itemNumber.ratio(64,MaxEnergy,energy));
        super.read(state, compound);
    }
    @Nonnull
    @Override
    public CompoundNBT write(@Nonnull CompoundNBT compound)
    {
        compound.putInt("BurnEnergy", this.energy);
        compound.put("UP",this.UP.serializeNBT());
        return super.write(compound);
    }

    //界面名
    @Override
    public ITextComponent getDisplayName() {
        return new TranslationTextComponent("gui." + examplemod.MODID + ".burn_container");
    }

    //创建界面
    @Nullable
    @Override
    public Container createMenu(int sycID, PlayerInventory inventory, PlayerEntity player) {
        return new ExampleBurnMachineContainers(sycID, inventory, this.pos, this.world, itemNumber);
    }

    //让实体具备交互的功能
    @Nonnull
    @Override
    public <T> LazyOptional<T> getCapability(@Nonnull Capability<T> cap, @Nullable Direction side) {
        //和forge的物品进行对比
        Capability<IItemHandler> itemHandlerCapability = CapabilityItemHandler.ITEM_HANDLER_CAPABILITY;
        if(cap.equals(itemHandlerCapability))
        {
            //方块的方向和交互口的方向是否一致
            if(Direction.UP.equals(side))
            {
                return LazyOptional.of(()->this.UP).cast();
            }
        }
        boolean isEnergy = Objects.equals(cap, CapabilityEnergy.ENERGY) && side.getAxis().isHorizontal();
        if(isEnergy)
        {
            return this.lazyOptional.cast();
        }
        return super.getCapability(cap, side);
    }

    public boolean MachineRun = false;
    public int compressorProgress = 0;
    public int brunTime = 0;

    public double brun = 0;

    //机器工作
    @Override
    public void tick() {
        if (this.world != null && !this.world.isRemote)
        {
            this.transferEnergy(this.world);
        }
        if(MaxEnergy == this.energy)
        {
            return;
        }
        if (!world.isRemote && MachineRun) {

            this.itemNumber.set(0, this.UP.getStackInSlot(0).getCount());
            this.itemNumber.set(1, itemNumber.ratio(64,MaxEnergy,energy));
            this.itemNumber.set(2, itemNumber.ratio(14,brun,brunTime *5));
            this.itemNumber.set(3,this.energy);
            //System.out.println(brun + " " + brunTime);
            //System.out.println(this.energy + "." + this.itemNumber.get(1));
            this.markDirty();
        }
        if(brunTime > 0)
        {
            brunTime--;
            if(brunTime <= 0)
            {
                //System.out.println("brun stop" + brunTime);
                if (!world.isRemote)
                    this.itemNumber.set(2, 0);
                MachineRun = false;
            }
            //增加能量
            int diff = Math.min(MaxEnergy - this.energy, 30);
            if (diff != 0)
            {
                this.energy += diff;
                if(!world.isRemote && MaxEnergy == this.energy)
                {
                    this.itemNumber.set(1, itemNumber.ratio(64,MaxEnergy,energy));
                    this.itemNumber.set(3,this.energy);
                }

                this.markDirty();
            }
        }
        Item item = this.UP.extractItem(0, 1, true).getItem();
        if(ForgeHooks.getBurnTime(new ItemStack(item), null) == 0)
        {
            //System.out.println("no brun");
            //机器正在运行 物品为空气 燃烧时间为0
            return;
        }
        if(!MachineRun && brunTime <= 0)
        {
            MachineRun = true;
            brunTime = ForgeHooks.getBurnTime(new ItemStack(item), null) / 5; //获取燃烧时间
            brun = (double)ForgeHooks.getBurnTime(new ItemStack(item), null);
            this.UP.extractItem(0,1,false); //减少一个物品
            markDirty();
            System.out.println("brun doing" + brunTime);
        }

        markDirty();

    }
    private static final int SLOTS = 1;//槽位





    //同步数据的数组
    private MyIntArray itemNumber = new MyIntArray();

    //能量体系
    private int energy = 0;
    private final int MaxEnergy = 192_000;

    private final LazyOptional<IEnergyStorage> lazyOptional = LazyOptional.of(() -> new IEnergyStorage()
    {
        @Override
        public int receiveEnergy(int maxReceive, boolean simulate)
        {
            return 0;
        }

        @Override
        public int extractEnergy(int maxExtract, boolean simulate)
        {
            int energy = this.getEnergyStored();
            int diff = Math.min(energy, maxExtract);
            if (!simulate)
            {
                ExampleBurnMachineTileEntity.this.energy -= diff;
                if (diff != 0)
                {
                    ExampleBurnMachineTileEntity.this.markDirty();
                }
            }
            return diff;
        }

        @Override
        public int getEnergyStored()
        {
            return Math.max(0, Math.min(this.getMaxEnergyStored(), ExampleBurnMachineTileEntity.this.energy));
        }

        @Override
        public int getMaxEnergyStored()
        {
            return MaxEnergy;
        }

        @Override
        public boolean canExtract()
        {
            return true;
        }

        @Override
        public boolean canReceive()
        {
            return false;
        }
    });

    private final Queue<Direction> directionQueue = Queues.newArrayDeque(Direction.Plane.HORIZONTAL); //水平面的方向加入队列
    private void transferEnergy(@Nonnull World world) {
        this.directionQueue.offer(this.directionQueue.remove()); //添加一个 删除一个 为了雨露均沾的发送电力
        //通过遍历水平方向的所有相邻方块，然后逐个注入能量，一次最多注入 500 FE。
        // 注意在获取相邻方块时，需要获取的是相反的方向（例如对于东侧的方块，
        // 注入能量时应该从该方块的西侧注入），也就是对 Direction 调用 getOpposite 方法并取其返回值。
        for (Direction direction : this.directionQueue) {
            TileEntity tileEntity = world.getTileEntity(this.pos.offset(direction));
            if (tileEntity != null) {
                tileEntity.getCapability(CapabilityEnergy.ENERGY, direction.getOpposite()).ifPresent(e ->
                {
                    if (e.canReceive()) {
                        int diff = e.receiveEnergy(Math.min(500, this.energy), false);
                        if (diff != 0) {
                            this.energy -= diff;
                            if (!world.isRemote)
                            {
                                this.itemNumber.set(3,this.energy);
                                this.itemNumber.set(1, itemNumber.ratio(64,MaxEnergy,energy));
                            }

                            this.markDirty();
                        }
                    }
                });
            }
        }

    }




}
